home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / book / Chap14 / Select / Select.c next >
Encoding:
C/C++ Source or Header  |  1999-08-18  |  7.5 KB  |  328 lines

  1. // Select.c
  2. // OpenGL SuperBible, Chapter 14
  3. // Demonstrates OpenGL Picking and Selection with feedback
  4. // Program by Richard S. Wright Jr.
  5.  
  6. #include <windows.h>
  7. #include <gl/gl.h>
  8. #include <gl/glu.h>
  9. #include <gl/glut.h>
  10. #include <math.h>
  11.  
  12.  
  13.  
  14. #define glRGB(x, y, z)    glColor3ub((GLubyte)x, (GLubyte)y, (GLubyte)z)
  15.  
  16. #define CUBE    1
  17. #define SPHERE    2
  18.  
  19. RECT bRect;            // Bounding rectangle
  20. GLuint nWho = 0;        // Who is selected
  21. float fAspect;
  22.  
  23. // Application name and instance storeage
  24. static LPCTSTR lpszAppName = "Select an Object";
  25. static HINSTANCE hInstance;
  26.  
  27. // Lighting values
  28. GLfloat  whiteLight[] = { 0.35f, 0.35f, 0.35f, 1.0f };
  29. GLfloat  sourceLight[] = { 0.65f, 0.65f, 0.65f, 1.0f };
  30. GLfloat     lightPos[] = { -500.0f, 500.0f, 600.0f, 1.0f };
  31.  
  32.  
  33.  
  34. // Render the cube and sphere
  35. void DrawObjects(void)
  36.     {
  37.     // Save the matrix state and do the rotations
  38.     glMatrixMode(GL_MODELVIEW);
  39.     glPushMatrix();
  40.  
  41.     // Translate the whole scene out and into view    
  42.     glTranslatef(-80.0f, 0.0f, -300.0f);    
  43.  
  44.     // Initialize the names stack
  45.     glInitNames();
  46.     glPushName(0);
  47.  
  48.     // Set material color, Yellow
  49.     // Cube
  50.     glRGB(255, 255, 0);
  51.     glLoadName(CUBE);
  52.     glPassThrough((GLfloat)CUBE);
  53.     glutSolidCube(75.0f);
  54.  
  55.  
  56.     // Draw Sphere
  57.     glRGB(128,0,0);
  58.     glTranslatef(130.0f, 0.0f, 0.0f);
  59.     glLoadName(SPHERE);
  60.     glPassThrough((GLfloat)SPHERE);    
  61.     glutSolidSphere(50.0f, 15, 15);
  62.  
  63.     // Restore the matrix state
  64.     glPopMatrix();    // Modelview matrix
  65.     }
  66.     
  67.  
  68. // Called to draw scene
  69. void RenderScene(void)
  70.     {
  71.     // Clear the window with current clearing color
  72.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  73.     
  74.     // Draw the objects in the scene
  75.     DrawObjects();
  76.  
  77.     // If something is selected, draw a bounding box around it
  78.     if(nWho != 0)
  79.         {
  80.         int viewport[4];
  81.         
  82.         // Get the viewport
  83.         glGetIntegerv(GL_VIEWPORT, viewport);
  84.  
  85.         // Remap the viewing volume to match window coordinates (approximately)
  86.         glMatrixMode(GL_PROJECTION);
  87.         glPushMatrix();
  88.         glLoadIdentity();
  89.         
  90.         // Establish clipping volume (left, right, bottom, top, near, far)
  91.         glOrtho(viewport[0], viewport[2], viewport[3], viewport[1], -1, 1);
  92.         glMatrixMode(GL_MODELVIEW);
  93.  
  94.         glDisable(GL_LIGHTING);
  95.         glColor3ub(255,0,0);        
  96.         glBegin(GL_LINE_LOOP);
  97.             glVertex2i(bRect.left, bRect.top);
  98.             glVertex2i(bRect.left, bRect.bottom);
  99.             glVertex2i(bRect.right, bRect.bottom);
  100.             glVertex2i(bRect.right, bRect.top);
  101.         glEnd();
  102.         glEnable(GL_LIGHTING);
  103.         }
  104.  
  105.     glMatrixMode(GL_PROJECTION);
  106.     glPopMatrix();
  107.     glMatrixMode(GL_MODELVIEW);
  108.  
  109.     glutSwapBuffers();
  110.     }
  111.  
  112.  
  113.  
  114.  
  115. // Go into feedback mode and draw a rectangle around the object
  116. #define FEED_BUFF_SIZE    4096
  117. void MakeSelection(int nChoice)
  118.     {
  119.     // Space for the feedback buffer
  120.     GLfloat feedBackBuff[FEED_BUFF_SIZE];
  121.  
  122.     // Storeage for counters, etc.
  123.     int size,i,j,count;
  124.  
  125.     // Initial minimum and maximum values
  126.     bRect.right = bRect.bottom = -999999.0f;
  127.     bRect.left = bRect.top =  999999.0f;
  128.  
  129.     // Set the feedback buffer
  130.     glFeedbackBuffer(FEED_BUFF_SIZE,GL_2D, feedBackBuff);
  131.  
  132.     // Enter feedback mode
  133.     glRenderMode(GL_FEEDBACK);
  134.  
  135.     // Redraw the scene
  136.     DrawObjects();
  137.  
  138.     // Leave feedback mode
  139.     size = glRenderMode(GL_RENDER);
  140.  
  141.     // Parse the feedback buffer and get the
  142.     // min and max X and Y window coordinates
  143.     i = 0;
  144.     while(i < size)
  145.         {
  146.         // Search for appropriate token
  147.         if(feedBackBuff[i] == GL_PASS_THROUGH_TOKEN)
  148.             if(feedBackBuff[i+1] == (GLfloat)nChoice)
  149.             {
  150.             i+= 2;
  151.             // Loop until next token is reached
  152.             while(i < size && feedBackBuff[i] != GL_PASS_THROUGH_TOKEN)
  153.                 {
  154.                 // Just get the polygons
  155.                 if(feedBackBuff[i] == GL_POLYGON_TOKEN)
  156.                     {
  157.                     // Get all the values for this polygon
  158.                     count = (int)feedBackBuff[++i]; // How many vertices
  159.                     i++;
  160.  
  161.                     for(j = 0; j < count; j++)    // Loop for each vertex
  162.                         {
  163.                         // Min and Max X
  164.                         if(feedBackBuff[i] > bRect.right)
  165.                             bRect.right = feedBackBuff[i];
  166.  
  167.                         if(feedBackBuff[i] < bRect.left)
  168.                             bRect.left = feedBackBuff[i];
  169.                         i++;
  170.  
  171.                         // Min and Max Y
  172.                         if(feedBackBuff[i] > bRect.bottom)
  173.                             bRect.bottom = feedBackBuff[i];
  174.  
  175.                         if(feedBackBuff[i] < bRect.top)
  176.                             bRect.top = feedBackBuff[i];
  177.                         i++;
  178.                         }
  179.                     }
  180.                 else
  181.                     i++;    // Get next index and keep looking
  182.                 }
  183.             break;
  184.             }
  185.         i++;
  186.         }
  187.     }
  188.  
  189.  
  190.  
  191. // Process the selection, which is triggered by a right mouse
  192. // click at (xPos, yPos).
  193. #define BUFFER_LENGTH 64
  194. void ProcessSelection(int xPos, int yPos)
  195.     {
  196.     // Space for selection buffer
  197.     GLuint selectBuff[BUFFER_LENGTH];
  198.  
  199.     // Hit counter and viewport storeage
  200.     GLint hits, viewport[4];
  201.  
  202.     // Setup selection buffer
  203.     glSelectBuffer(BUFFER_LENGTH, selectBuff);
  204.     
  205.     // Get the viewport
  206.     glGetIntegerv(GL_VIEWPORT, viewport);
  207.  
  208.     // Switch to projection and save the matrix
  209.     glMatrixMode(GL_PROJECTION);
  210.     glPushMatrix();
  211.  
  212.     // Change render mode
  213.     glRenderMode(GL_SELECT);
  214.  
  215.     // Establish new clipping volume to be unit cube around
  216.     // mouse cursor point (xPos, yPos) and extending two pixels
  217.     // in the vertical and horzontal direction
  218.     glLoadIdentity();
  219.     gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
  220.  
  221.     // Apply perspective matrix 
  222.     gluPerspective(60.0f, fAspect, 1.0, 425.0);
  223.  
  224.     // Draw the scene
  225.     DrawObjects();
  226.  
  227.     // Collect the hits
  228.     hits = glRenderMode(GL_RENDER);
  229.  
  230.     // Restore the projection matrix
  231.     glMatrixMode(GL_PROJECTION);
  232.     glPopMatrix();
  233.  
  234.     // Go back to modelview for normal rendering
  235.     glMatrixMode(GL_MODELVIEW);
  236.  
  237.     // If a single hit occured, display the info.
  238.     if(hits == 1)
  239.         {
  240.         MakeSelection(selectBuff[3]);
  241.         if(nWho == selectBuff[3])
  242.             nWho = 0;
  243.         else
  244.             nWho = selectBuff[3];
  245.         }
  246.  
  247.     glutPostRedisplay();
  248.     }
  249.  
  250.  
  251.  
  252.  
  253. // This function does any needed initialization on the rendering
  254. // context.  Here it sets up and initializes the lighting for
  255. // the scene.
  256. void SetupRC()
  257.     {
  258.     // Light values and coordinates
  259.     glEnable(GL_DEPTH_TEST);    // Hidden surface removal
  260.     glFrontFace(GL_CCW);        // Counter clock-wise polygons face out
  261.     //glEnable(GL_CULL_FACE);        // Do not calculate insides
  262.  
  263.     // Enable lighting
  264.     glEnable(GL_LIGHTING);
  265.  
  266.     // Setup and enable light 0
  267.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight);
  268.     glLightfv(GL_LIGHT0,GL_DIFFUSE,sourceLight);
  269.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  270.     glEnable(GL_LIGHT0);
  271.  
  272.     // Enable color tracking
  273.     glEnable(GL_COLOR_MATERIAL);
  274.     
  275.     // Set Material properties to follow glColor values
  276.     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  277.  
  278.     // Black blue background
  279.     glClearColor(0.60f, 0.60f, 0.60f, 1.0f );
  280.     glLineWidth(2.0f);
  281.     }
  282.  
  283.  
  284. void ChangeSize(int w, int h)
  285.     {
  286.     // Prevent a divide by zero
  287.     if(h == 0)
  288.         h = 1;
  289.  
  290.     // Set Viewport to window dimensions
  291.     glViewport(0, 0, w, h);
  292.  
  293.     // Calculate aspect ratio of the window
  294.     fAspect = (GLfloat)w/(GLfloat)h;
  295.  
  296.     // Set the perspective coordinate system
  297.     glMatrixMode(GL_PROJECTION);
  298.     glLoadIdentity();
  299.  
  300.     // Field of view of 45 degrees, near and far planes 1.0 and 425
  301.     gluPerspective(60.0f, fAspect, 1.0, 425.0);
  302.  
  303.     // Modelview matrix reset
  304.     glMatrixMode(GL_MODELVIEW);
  305.     glLoadIdentity();
  306.     }
  307.  
  308. // Process the mouse click
  309. void MouseCallback(int button, int state, int x, int y)
  310.     {
  311.     if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
  312.         ProcessSelection(x, y);
  313.     }
  314.  
  315. int main(int argc, char* argv[])
  316.     {
  317.     glutInit(&argc, argv);
  318.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  319.     glutCreateWindow("Select an Object");
  320.     glutReshapeFunc(ChangeSize);
  321.     glutMouseFunc(MouseCallback);
  322.     glutDisplayFunc(RenderScene);
  323.     SetupRC();
  324.     glutMainLoop();
  325.  
  326.     return 0;
  327.     }
  328.